#if !defined(ximera_math_quaternion_hpp)
#define ximera_math_quaternion_hpp

// -----------------------------------------------------------

#include <ximera/math/matrix3.hpp>
#include <ximera/math/vector3.hpp>

namespace ximera { namespace math
{
    class XIMERA_API Quaternion
    {
    public:
        Real w, x, y, z;

    public:
        Quaternion(Real w = 1, Real x = 0, Real y = 0, Real z = 0);
        Quaternion(Real const* wxyz);
        Quaternion(Matrix3 const& rotMat);
        Quaternion(Vector3 const& axis, Real angle);

        void fromRotationMatrix(Matrix3 const& rotMat);
        void toRotationMatrix(Matrix3& rotMat) const;

        void fromAxisAngle(Vector3 const& axis, Real angle);
        void toAxisAngle(Vector3& axis, Real& angle) const;
        
        Real length() const;
        Real lengthSquared() const;

        Real dotProduct(Quaternion const& vec) const;
        Quaternion& multiply(Quaternion const& quat);

        Quaternion& normalize();
        Quaternion asNormal() const;

        Quaternion& inverse();
        Quaternion asInverse() const;

        Real& operator[](int i);
        Real const& operator[](int i) const;

        Real* array();
        Real const* array() const;

        Quaternion operator-() const;

        Quaternion& operator+=(Quaternion const& rhs);
        Quaternion& operator-=(Quaternion const& rhs);
        Quaternion& operator*=(Real rhs);
        Quaternion& operator/=(Real rhs);

        static Quaternion const ZERO;
        static Quaternion const IDENTITY;
    };

    // Quaternion-Quaternion arithmetic
    Quaternion operator-(Quaternion const& lhs, Quaternion const& rhs);
    Quaternion operator+(Quaternion const& lhs, Quaternion const& rhs);
    Quaternion operator*(Quaternion const& lhs, Quaternion const& rhs);

    // Quaternion-Real arithmetic
    Quaternion operator*(Quaternion const& lhs, Real rhs);
    Quaternion operator*(Real lhs, Quaternion const& rhs);
    Quaternion operator/(Quaternion const& lhs, Real rhs);

    // Comparisons
    bool operator==(Quaternion const& lhs, Quaternion const& rhs);
    bool operator!=(Quaternion const& lhs, Quaternion const& rhs);
    bool operator<(Quaternion const& lhs, Quaternion const& rhs);
    bool operator>(Quaternion const& lhs, Quaternion const& rhs);
}}

#include <ximera/math/inline/quaternion.inl>

// -----------------------------------------------------------

#endif